﻿using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Data;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using DotNetCommon;
using DotNetCommon.Data;
using DotNetCommon.Extensions;
using System.Data.Common;
using System.Reflection;
using System.Linq.Expressions;
using DotNetCommon.Logger;
using System.Text;
using System.Diagnostics;

namespace DBUtil
{
    /// <summary>
    /// 通用数据库访问对象
    /// </summary>
    public abstract partial class DBAccess
    {
        #region 执行sql语句 ExecuteSql...

        public virtual int ExecuteSql(string strSql)
            => ExecuteSql(strSql, null, null, new DbParameter[0]);

        public virtual int ExecuteSql(string strSql, IDictionary<string, object> parameters)
            => ExecuteSql(strSql, null, null, parameters?.Keys.Select(key => CreatePara(key, parameters[key])).ToArray());

        public virtual int ExecuteSql(string strSql, params DbParameter[] parameters)
            => ExecuteSql(strSql, null, null, parameters);

        public virtual int ExecuteSql(string strSql, CommandType? commandType, int? timeoutSecond, params DbParameter[] parameters)
        {
            var cmd = createCommand(commandType, timeoutSecond, strSql, parameters);
            return RunInConnection(() =>
            {
                var res = cmd.ExecuteNonQuery();
                cmd.Parameters?.Clear();
                return res;
            });
        }
        #endregion

        #region Insert...
        /// <summary>
        /// 向一个表批量插入,示例：
        /// <list type="number">
        /// <item>Insert("test", new { name = "小明" }.ToDictionary(), new { name = "小王", age = 18 }.ToDictionary());</item>
        /// </list>
        /// </summary>
        public virtual int Insert(string tableName, params IDictionary<string, object>[] dics)
        {
            var (sql, paras) = InsertToSql(tableName, dics);
            return ExecuteSql(sql, paras);
        }

        /// <summary>
        /// 批量插入数据(可批量向不同表插入),示例：
        /// <list type="number">
        /// <item>InsertBatch(InsertBatchItem.Create("test1", new { name = "小明" }.ToDictionary()), InsertBatchItem.Create("test2", new { name = "小王", age = 18 }.ToDictionary()))</item>
        /// </list>
        /// </summary>
        public virtual int InsertBatch(params InsertBatchItem[] items)
        {
            var (sql, paras) = InsertBatchToSql(items);
            return ExecuteSql(sql, paras);
        }

        /// <summary>
        /// 插入一行数据并且返回自增的Id（也可以是来自序列的自增id），示例：
        /// <list type="number">
        /// <item>var id = InsertAndGetId("test", new { name="小明"}.ToDictionary())</item>
        /// </list>
        /// </summary>
        public virtual long InsertAndGetId(string tableName, IDictionary<string, object> dic)
        {
            var (sql, paras) = InsertAndGetIdToSql(tableName, dic);
            return SelectScalar<long>(sql, paras);
        }

        /// <summary>
        /// 插入多行数据(相同表)并且返回自增的Id集合,认为自增步长为1，示例：
        /// <list type="number">
        /// <item>var ids = InsertAndGetIds("test", null, new { name = "小明" }.ToDictionary(), new { name = "小王" }.ToDictionary());</item>
        /// </list>
        /// </summary>
        public virtual List<long> InsertAndGetIds(string tableName, params IDictionary<string, object>[] dics)
        {
            var (sql, paras) = InsertAndGetIdsToSql(tableName, dics);
            var id = SelectScalar<long>(sql, paras);
            var ids = new List<long>();
            //假设id自增为1,比如: 基础为1,插入三条(id=2,3,4),返回:4, 最终计算出: [2,3,4]
            for (int i = 0, len = dics.Length; i < len; i++)
            {
                ids.Add(id - len + i + 1);
            }
            return ids;
        }

        #region Insert...ToSql

        protected virtual (string sql, IDictionary<string, object> paras) InsertToSql(string tableName, params IDictionary<string, object>[] dics)
        {
            if (tableName.IsNullOrEmptyOrWhiteSpace()) throw new ArgumentException(nameof(tableName));
            if (dics.IsNullOrEmpty()) throw new ArgumentException(nameof(dics));
            //校验字典键是否相同
            var keys = dics.FirstOrDefault().Keys.ToList();
            if (dics.Length > 1)
            {
                for (int i = 1, len = dics.Length; i < len; i++)
                {
                    var dic = dics[i];
                    var t = dic.Keys.ToList();
                    foreach (var key2 in t)
                    {
                        if (!keys.Contains(key2)) keys.Add(key2);
                    }
                }
            }
            var sql = $"insert into {tableName}({keys.ToStringSeparated(",")})";
            var inserts = new List<string>();
            var paras = new Dictionary<string, object>();
            for (var i = 0; i < dics.Length; i++)
            {
                var dic = dics[i];
                var prefix = GetCounter();
                var list = new List<string>();
                foreach (var key in keys)
                {
                    if (!dic.TryGetValue(key, out var item))
                    {
                        item = null;
                    }
                    var res = ConvertToSqlSegment(item);
                    if (res.Success)
                    {
                        list.Add(res.Data);
                        continue;
                    }
                    var name = $"p{prefix}_{key}";
                    list.Add(ParaPrefix + name);
                    paras.Add(name, item);
                }
                inserts.Add("(" + list.ToStringSeparated(",") + ")");
            }
            if (inserts.Count == 1)
            {
                sql += $" values{inserts.FirstOrDefault()};";
            }
            else
            {
                sql += $" values\r\n";
                var t = inserts.Select(i => $"    {i}").ToStringSeparated(",\r\n");
                sql += t + ";";
            }
            return (sql, paras);
        }

        protected virtual (string sql, IDictionary<string, object> paras) InsertAndGetIdsToSql(string tableName, params IDictionary<string, object>[] dics)
        {
            var (sql, paras) = InsertToSql(tableName, dics);
            var sqlid = GetInsertedId();
            sql += "\r\n" + sqlid;
            return (sql, paras);
        }

        protected virtual (string sql, IDictionary<string, object> paras) InsertAndGetIdToSql(string tableName, IDictionary<string, object> dic) => InsertAndGetIdsToSql(tableName, dic);


        protected virtual (string sql, IDictionary<string, object> paras) InsertBatchToSql(params InsertBatchItem[] items)
        {
            var sqls = new List<string>();
            var paras = new Dictionary<string, object>();
            for (int i = 0; i < items.Length; i++)
            {
                var item = items[i];
                var (sql2, paras2) = InsertToSql(item.TableName, item.Dic);
                sqls.Add(sql2);
                paras.Add(paras2);
            }
            return (sqls.ToStringSeparated("\r\n"), paras);
        }
        #endregion

        #endregion

        #region Update...
        protected virtual (string filterSql, IDictionary<string, object> paras) WhereToSql(IDictionary<string, object> fitlerDic)
        {
            var filterSql = "";
            var paras = new Dictionary<string, object>();
            if (fitlerDic.IsNullOrEmpty()) return (filterSql, paras);

            var keys = fitlerDic.Keys.ToList();
            var list = new List<(string col, string val)>();
            var prefix = GetCounter();
            for (var i = 0; i < keys.Count; i++)
            {
                var key = keys[i];
                var val = fitlerDic[key];
                var name = $"p{prefix}_{key}";
                list.Add((key, ParaPrefix + name));
                paras.Add(name, val);
            }
            filterSql = $" and ({list.Select(i => $"{i.col}={i.val}").ToStringSeparated(" and ")})";
            return (filterSql, paras);
        }

        /// <summary>
        /// 更新数据,示例：
        /// <list type="number">
        /// <item>Update("test", new { name = "小明" }.ToDictionary(), "and id=1");</item>
        /// <item>Update("test", new { name = "小明" }.ToDictionary(), "and id=@id", new { id = 1 }.ToDictionary());</item>
        /// </list>
        /// </summary>
        public virtual int Update(string tableName, IDictionary<string, object> setDic, string whereSql, IDictionary<string, object> parameters = null)
        {
            var (sql, paras) = UpdateToSql(UpdateBatchItem.Create(tableName, setDic, whereSql, parameters));
            return ExecuteSql(sql, paras);
        }

        /// <summary>
        /// 更新数据，示例：
        /// <list type="number">
        /// <item>Update("test", new { name = "小明" }.ToDictionary(),  new { id = 1 }.ToDictionary())</item>
        /// </list>
        /// </summary>
        public virtual int Update(string tableName, IDictionary<string, object> setDic, IDictionary<string, object> whereDic)
        {
            var (sql, paras) = UpdateToSql(UpdateBatchItem.Create(tableName, setDic, whereDic));
            return ExecuteSql(sql, paras);
        }

        /// <summary>
        /// 批量更新,不同表，示例：
        /// <list type="number">
        /// <item>UpdateBatch(<br/>
        /// UpdateBatchItem.Create("test1", new { name = "小明" }.ToDictionary(), "and id=1"),<br/>
        /// UpdateBatchItem.Create("test2", new { name = "小明2" }.ToDictionary(), new { id = 1 }.ToDictionary())<br/>
        /// );</item>
        /// </list>
        /// </summary>
        public virtual int UpdateBatch(params UpdateBatchItem[] items)
        {
            var sqls = new List<string>();
            var paras = new Dictionary<string, object>();
            foreach (var item in items)
            {
                var (sql2, para2) = UpdateToSql(item);
                sqls.Add(sql2);
                paras.Add(para2);
            }
            var sql = sqls.ToStringSeparated("\r\n");
            return ExecuteSql(sql, paras);
        }

        protected virtual (string sql, IDictionary<string, object> paras) UpdateToSql(UpdateBatchItem item)
        {
            var sql = $"update {item.TableName} set ";

            var setDic = item.SetDic;
            var keys = setDic.Keys.ToList();
            var list = new List<(string col, string val)>();
            var paras = new Dictionary<string, object>();
            var prefix = GetCounter();
            for (int i = 0, len = keys.Count; i < len; i++)
            {
                var key = keys[i];
                var value = setDic[key];
                var res = ConvertToSqlSegment(value);
                if (res.Success)
                {
                    list.Add((key, res.Data));
                    continue;
                }
                var name = $"p{prefix}_{key}";
                list.Add((key, ParaPrefix + name));
                paras.Add(name, value);
            }

            sql += list.Select(i => $"{i.col}={i.val}").ToStringSeparated(",");
            list.Clear();

            if (item.UseRawSql)
            {
                if (!item.WhereSql.IsNullOrEmptyOrWhiteSpace())
                {
                    var t = item.WhereSql.TrimStart(' ').ToUpper();
                    if (t.StartsWith("WHERE ")) sql += " " + item.WhereSql.TrimStart(' ');
                    else if (t.StartsWith("AND") || t.StartsWith("OR")) sql += " where 1=1 " + item.WhereSql.TrimStart(' ');
                    else sql += "where " + item.WhereSql.TrimStart(' ');
                    if (item.WhereDic.IsNotNullOrEmpty()) paras.Add(item.WhereDic);
                }
            }
            else
            {
                if (item.WhereDic.IsNotNullOrEmpty())
                {
                    var (fitlerSql, paras2) = WhereToSql(item.WhereDic);
                    sql += $" where 1=1 {fitlerSql}";
                    if (paras2.IsNotNullOrEmpty()) paras.Add(paras2);
                }
            }
            sql += ";";
            return (sql, paras);
        }
        #endregion

        #region UpdateOrInsert
        /// <summary>
        /// 插入或更新，示例：
        /// <list type="number">
        /// <item>UpdateOrInsert("test", new { id = 1, name = "小明2" }.ToDictionary(), new { name = "小明2" }.ToDictionary(), "and id=1");</item>
        /// <item>UpdateOrInsert("test", new { id = 1, name = "小明2" }.ToDictionary(), new { name = "小明2" }.ToDictionary(), "and id=@id", new { id = 1 }.ToDictionary());</item>
        /// </list>
        /// </summary>
        public virtual int UpdateOrInsert(string tableName, IDictionary<string, object> insertDic, IDictionary<string, object> updateDic, string whereSql, IDictionary<string, object> parameters = null)
        {
            var filterSql = "";
            if (whereSql.IsNotNullOrEmptyOrWhiteSpace())
            {
                var t = whereSql.TrimStart(' ').ToUpper();
                if (t.StartsWith("WHERE")) filterSql = $" {whereSql.TrimStart(' ')}";
                else if (t.StartsWith("AND") || t.StartsWith("OR")) filterSql = $" where 1=1 {whereSql.TrimStart(' ')}";
                else filterSql = $" where {whereSql.TrimStart(' ')}";
            }
            return RunInConnection(() =>
            {
                if (SelectScalar<int>($"select count(1) from {tableName} {filterSql};", parameters) == 0)
                {
                    return Insert(tableName, insertDic);
                }
                else
                {
                    return Update(tableName, updateDic, whereSql, parameters);
                }
            });
        }

        /// <summary>
        /// 插入或更新，示例：
        /// <list type="number">
        /// <item>UpdateOrInsert("test", new { id = 1, name = "小明2" }.ToDictionary(), new { name = "小明2" }.ToDictionary(), new { id = 1 }.ToDictionary());</item>
        /// </list>
        /// </summary>
        public virtual int UpdateOrInsert(string tableName, IDictionary<string, object> insertDic, IDictionary<string, object> updateDic, IDictionary<string, object> filterDic)
        {
            if (filterDic.IsNullOrEmpty()) return UpdateOrInsert(tableName, insertDic, updateDic, string.Empty);
            var (filterSql, paras) = WhereToSql(filterDic);
            var sql = $"select count(1) from {tableName} where 1=1 {filterSql}";
            if (SelectScalar<int>(sql, paras) == 0)
            {
                return Insert(tableName, insertDic);
            }
            else
            {
                return Update(tableName, updateDic, filterSql, paras);
            }
        }
        #endregion

        #region Delete
        /// <summary>
        /// 删除数据，示例：
        /// <list type="number">
        /// <item>Delete("test","and id=@id",new { id=1}.ToDictionary())</item>
        /// <item>Delete("test","id=:id",new { id=1}.ToDictionary())</item>
        /// </list>
        /// </summary>
        public virtual int Delete(string tableName, string whereSql, IDictionary<string, object> parameters = null)
        {
            var item = DeleteBatchItem.Create(tableName, whereSql, parameters);
            var (sql, paras) = DeleteToSql(item);
            return ExecuteSql(sql, paras);
        }

        /// <summary>
        /// 删除数据，示例：
        /// <list type="number">
        /// <item>Delete("test", new { id = 1 }.ToDictionary());</item>
        /// </list>
        /// </summary>
        public virtual int Delete(string tableName, IDictionary<string, object> whereDic)
        {
            var item = DeleteBatchItem.Create(tableName, whereDic);
            var (sql, paras) = DeleteToSql(item);
            return ExecuteSql(sql, paras);
        }

        /// <summary>
        /// 批量删除(不同表)，示例：
        /// <list type="number">
        /// <item>DeleteBatch(DeleteBatchItem.Create("test1", "and id=1"), DeleteBatchItem.Create("test2", new { id = 2 }.ToDictionary()));</item>
        /// </list>
        /// </summary>
        public virtual int DeleteBatch(params DeleteBatchItem[] items)
        {
            var sqls = new List<string>();
            var paras = new Dictionary<string, object>();
            for (var i = 0; i < items.Length; i++)
            {
                var (sql2, para2) = DeleteToSql(items[i]);
                sqls.Add(sql2);
                if (para2.IsNotNullOrEmpty()) paras.Add(para2);
            }
            var sql = sqls.ToStringSeparated("\r\n");
            return ExecuteSql(sql, paras);
        }

        protected virtual (string sql, IDictionary<string, object> parameters) DeleteToSql(DeleteBatchItem item)
        {
            var sql = $"delete from {item.TableName}";
            var paras = new Dictionary<string, object>();
            if (item.UseRawSql)
            {
                if (item.WhereSql.IsNotNullOrEmptyOrWhiteSpace())
                {
                    var t = item.WhereSql.TrimStart(' ').ToUpper();
                    if (t.StartsWith("WHERE")) sql += " " + item.WhereSql.TrimStart(' ');
                    else if (t.StartsWith("AND") || t.StartsWith("OR")) sql += " where 1=1 " + item.WhereSql.TrimStart(' ');
                    else sql += " where " + item.WhereSql.TrimStart(' ');
                }
                return (sql, item.WhereDic);
            }
            if (item.WhereDic.IsNotNullOrEmpty())
            {
                var (sql2, paras2) = WhereToSql(item.WhereDic);
                if (sql2.IsNotNullOrEmptyOrWhiteSpace())
                {
                    sql += $" where 1=1 {sql2}";
                }
                return (sql, paras2);
            }
            return (sql, null);
        }
        #endregion

        #region 查询语句 Select...

        #region SelectScalar
        public virtual T SelectScalar<T>(string strSql) => SelectScalar<T>(strSql, null, null, new DbParameter[0]);

        public virtual T SelectScalar<T>(string strSql, IDictionary<string, object> parameters)
            => SelectScalar<T>(strSql, null, null, parameters?.Select(i => CreatePara(i.Key, i.Value)).ToArray());

        public virtual T SelectScalar<T>(string strSql, params DbParameter[] parameters)
            => SelectScalar<T>(strSql, null, null, parameters);

        public virtual T SelectScalar<T>(string strSql, CommandType? commandType, int? timeoutSecond, params DbParameter[] parameters)
        {
            object res = null;
            var cmd = createCommand(commandType, timeoutSecond, strSql, parameters);
            res = RunInConnection(() => cmd.ExecuteScalar());
            cmd.Parameters?.Clear();
            return res.To<T>();
        }
        #endregion

        #region SelectDataSet
        public virtual DataSet SelectDataSet(string strSql)
            => SelectDataSet(strSql, null, null, new DbParameter[0]);

        public virtual DataSet SelectDataSet(string strSql, params DbParameter[] parameters)
            => SelectDataSet(strSql, null, null, parameters);

        public virtual DataSet SelectDataSet(string strSql, IDictionary<string, object> parameters)
            => SelectDataSet(strSql, null, null, parameters?.Select(x => CreatePara(x.Key, x.Value)).ToArray());

        public virtual DataSet SelectDataSet(string strSql, CommandType? commandType, int? timeoutSecond, params DbParameter[] parameters)
        {
            DataSet set = new DataSet();
            var cmd = createCommand(commandType, timeoutSecond, strSql, parameters);
            var adp = CreateAdapter(cmd);
            RunInConnection(() => adp.Fill(set));
            cmd.Parameters?.Clear();
            return set;
        }
        #endregion

        #region SelectDataTable
        public virtual DataTable SelectDataTable(string strSql)
            => SelectDataTable(strSql, null, null, new DbParameter[0]);

        public virtual DataTable SelectDataTable(string strSql, IDictionary<string, object> parameters)
            => SelectDataTable(strSql, null, null, parameters?.Select(x => CreatePara(x.Key, x.Value)).ToArray());

        public virtual DataTable SelectDataTable(string strSql, params DbParameter[] parameters)
            => SelectDataTable(strSql, null, null, parameters);

        public virtual DataTable SelectDataTable(string strSql, CommandType? commandType, int? timeoutSecond, params DbParameter[] parameters)
            => SelectDataSet(strSql, commandType, timeoutSecond, parameters).Tables[0];
        #endregion

        #region SelectDataReader

        #region SelectDataReader Action
        public virtual void SelectDataReader(Action<DbDataReader> action, string strSql)
            => SelectDataReader(action, strSql, null, null, new DbParameter[0]);

        public virtual void SelectDataReader(Action<DbDataReader> action, string strSql, params DbParameter[] parameters)
            => SelectDataReader(action, strSql, null, null, parameters);

        public virtual void SelectDataReader(Action<DbDataReader> action, string strSql, IDictionary<string, object> parameters)
            => SelectDataReader(action, strSql, null, null, parameters?.Select(x => CreatePara(x.Key, x.Value)).ToArray());

        public virtual void SelectDataReader(Action<DbDataReader> action, string strSql, CommandType? commandType, int? timeoutSecond, params DbParameter[] parameters)
        {
            if (action == null) throw new Exception("执行逻辑不能为空!");
            var cmd = createCommand(commandType, timeoutSecond, strSql, parameters);
            RunInConnection(() =>
            {
                var reader = cmd.ExecuteReader();
                readers.Push(reader);
                try
                {
                    action.Invoke(reader);
                }
                finally
                {
                    if (!reader.IsClosed)
                        try { reader.Close(); } catch { }
                    cmd.Parameters?.Clear();
                    readers.Pop();
                }
            });
        }
        #endregion

        #region SelectDataReader Func
        public virtual T SelectDataReader<T>(Func<DbDataReader, T> func, string strSql)
            => SelectDataReader(func, strSql, null, null, new DbParameter[0]);

        public virtual T SelectDataReader<T>(Func<DbDataReader, T> func, string strSql, params DbParameter[] parameters)
            => SelectDataReader(func, strSql, null, null, parameters);

        public virtual T SelectDataReader<T>(Func<DbDataReader, T> func, string strSql, IDictionary<string, object> parameters)
            => SelectDataReader(func, strSql, null, null, parameters?.Select(x => CreatePara(x.Key, x.Value)).ToArray());

        public virtual T SelectDataReader<T>(Func<DbDataReader, T> func, string strSql, CommandType? commandType, int? timeoutSecond, params DbParameter[] parameters)
        {
            if (func == null) throw new Exception("执行逻辑不能为空!");
            var cmd = createCommand(commandType, timeoutSecond, strSql, parameters);
            return RunInConnection(() =>
            {
                var reader = cmd.ExecuteReader();
                readers.Push(reader);
                try
                {
                    T result = default(T);
                    if (func != null) result = func(reader);
                    return result;
                }
                finally
                {
                    if (!reader.IsClosed)
                        try { reader.Close(); } catch { }
                    cmd.Parameters?.Clear();
                    readers.Pop();
                }
            });
        }
        #endregion

        #endregion

        #region SelectModel

        #region SelectModel
        public virtual T SelectModel<T>(string sql) where T : class, new()
            => SelectModel<T>(sql, null, null, new DbParameter[0]);

        public virtual T SelectModel<T>(string sql, IDictionary<string, object> parameters) where T : class, new()
            => SelectModel<T>(sql, null, null, parameters?.Select(x => CreatePara(x.Key, x.Value)).ToArray());

        public virtual T SelectModel<T>(string sql, params DbParameter[] parameters) where T : class, new()
            => SelectModel<T>(sql, null, null, parameters);

        public virtual T SelectModel<T>(string sql, CommandType? commandType, int? timeoutSecond, params DbParameter[] parameters) where T : class, new()
        {
            return SelectDataReader<T>(reader =>
            {
                if (!reader.Read())
                    return null;
                var exp = GetFunc<T>(reader);
                var inst = exp(reader);
                return inst;
            }, sql, commandType, timeoutSecond, parameters);
        }
        #endregion

        #region SelectModelList
        public virtual List<T> SelectModelList<T>(string sql) where T : class, new()
            => SelectModelList<T>(sql, null, null, new DbParameter[0]);

        public virtual List<T> SelectModelList<T>(string sql, params DbParameter[] parameters) where T : class, new()
           => SelectModelList<T>(sql, null, null, parameters);

        public virtual List<T> SelectModelList<T>(string sql, IDictionary<string, object> parameters) where T : class, new()
          => SelectModelList<T>(sql, null, null, parameters?.Select(x => CreatePara(x.Key, x.Value)).ToArray());

        public virtual List<T> SelectModelList<T>(string sql, CommandType? commandType, int? timeoutSecond, params DbParameter[] parameters) where T : class, new()
        {
            return SelectDataReader(reader =>
            {
                var list = new List<T>();
                var exp = GetFunc<T>(reader);
                while (reader.Read())
                {
                    var inst = exp(reader);
                    list.Add(inst);
                }
                return list;
            }, sql, commandType, timeoutSecond, parameters);
        }
        #endregion

        #endregion

        #region SelectDictionary

        #region SelectDictionary
        public virtual Dictionary<string, object> SelectDictionary(string sql)
            => SelectDictionary(sql, null, null, new DbParameter[0]);

        public virtual Dictionary<string, object> SelectDictionary(string sql, params DbParameter[] parameters)
            => SelectDictionary(sql, null, null, parameters);

        public virtual Dictionary<string, object> SelectDictionary(string sql, IDictionary<string, object> parameters)
            => SelectDictionary(sql, null, null, parameters?.Select(x => CreatePara(x.Key, x.Value)).ToArray());

        public virtual Dictionary<string, object> SelectDictionary(string sql, CommandType? commandType, int? timeoutSecond, params DbParameter[] parameters)
        {
            return SelectDataReader(reader =>
            {
                Dictionary<string, object> dic = null;
                var count = reader.FieldCount;
                if (reader.Read())
                {
                    dic = new Dictionary<string, object>();
                    for (int i = 0; i < count; i++)
                    {
                        dic[reader.GetName(i)] = reader.GetValue(i);
                    }
                }
                return dic;
            }, sql, commandType, timeoutSecond, parameters);
        }
        #endregion

        #region SelectDictionaryList
        public virtual List<Dictionary<string, object>> SelectDictionaryList(string sql)
            => SelectDictionaryList(sql, null, null, new DbParameter[0]);

        public virtual List<Dictionary<string, object>> SelectDictionaryList(string sql, params DbParameter[] parameters)
            => SelectDictionaryList(sql, null, null, parameters);

        public virtual List<Dictionary<string, object>> SelectDictionaryList(string sql, IDictionary<string, object> parameters)
            => SelectDictionaryList(sql, null, null, parameters?.Select(x => CreatePara(x.Key, x.Value)).ToArray());

        public virtual List<Dictionary<string, object>> SelectDictionaryList(string sql, CommandType? commandType, int? timeoutSecond, params DbParameter[] parameters)
        {
            return SelectDataReader(reader =>
            {
                var count = reader.FieldCount;
                var names = new string[count];
                for (int i = 0; i < count; i++)
                {
                    names[i] = reader.GetName(i);
                }
                var list = new List<Dictionary<string, object>>();
                while (reader.Read())
                {
                    var dic = new Dictionary<string, object>();
                    list.Add(dic);
                    for (int i = 0; i < count; i++)
                    {
                        dic[names[i]] = reader.GetValue(i);
                    }
                }
                return list;
            }, sql, commandType, timeoutSecond, parameters);
        }
        #endregion

        #endregion

        #endregion
    }
}
